/*
 * CC3GLMatrix.h
 *
 * cocos3d 0.6.1
 * Author: Bill Hollings
 * Copyright (c) 2010-2011 The Brenwill Workshop Ltd. All rights reserved.
 * http://www.brenwill.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://en.wikipedia.org/wiki/MIT_License
 */

/** @file */	// Doxygen marker
#ifndef __CC3GLMATRIX_H__
#define __CC3GLMATRIX_H__

#include "CC3Foundation.h"
#include "cocos2d.h"

/**
 * A wrapper class for a 4x4 OpenGL matrix array.
 *
 * This matrix wrapper is implemented as a class cluster design pattern.
 * Different concrete implementation classes are provided to handle different underlying
 * matrix data storage requirements. You do not need to be aware of the concrete classes,
 * which aare selected and instantiated automatically by the class allocation methods.
 */
//@interface CC3GLMatrix : NSObject <NSCopying> {
//	BOOL isIdentity;
//}
//
///**
// * Returns a pointer to the underlying array of 16 GLfloats stored in column-major order.
// * This can be passed directly into the standard OpenGL ES matrix functions.
// */
//@property(nonatomic, readonly) GLfloat* glMatrix;
//
///** 
// * Indicates whether this matrix is an identity matrix.
// *
// * This can be useful for short-circuiting many otherwise consumptive calculations.
// * For example, this class is implemented so that, matrix multiplication is not
// * performed as a raw calculation if one of the matrices is an identity matrix.
// * In addition, transposition and inversion of an identity matrix are no-ops.
// *
// * This values is set to YES after the matrix is initialized or populated as an
// * identity matrix, or populated by an identity transform. It is set to NO whenever
// * an operation is performed on this matrix that no longer results in it being an
// * identity matrix.
// *
// * This flag is only set to YES if the matrix is deliberately populated as an
// * identity matrix. It will not be set to YES if an operation results in the
// * contents of this matrix matching those of an identity matrix by accident.
// */
//@property(nonatomic, readonly) BOOL isIdentity;
//
//
//#pragma mark Allocation and initialization
//
///** Returns an initialized instance with all elements set to zero. */
//-(id) init;
//
///** Allocates and returns an initialized autoreleased instance with all elements set to zero. */
//+(id) matrix;
//
///**
// * Returns an initialized instance with all elements populated as an identity matrix
// * (ones on the diagonal, zeros elsewhere).
// */
//-(id) initIdentity;
//
///**
// * Allocates and returns an initialized autoreleased instance with all elements
// * populated as an identity matrix (ones on the diagonal, zeros elsewhere).
// */
//+(id) identity;
//
///**
// * Returns an initialized instance with all elements copied from the specified
// * GL matrix, which must be a standard 4x4 OpenGL matrix in column-major order.
// */
//-(id) initFromGLMatrix: (GLfloat*) aGLMtx;
//
///**
// * Allocates and returns an initialized autoreleased instance with all elements copied from
// * the specified GL matrix, which must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(id) matrixFromGLMatrix: (GLfloat*) aGLMtx;
//
///**
// * Returns an initialized instance that wraps the specified GL matrix, which must be a
// * standard 4x4 OpenGL matrix in column-major order. Changes to this matrix instance will
// * change the underlying data passed here. This is useful when the matrix data was supplied
// * and loaded by some other mechanism, such as a file loader. Rather than copying the data
// * into a new matrix, resulting in two copies of the matrix data, a CC3GLMatrix instance
// * can be initialized to wrap the data.
// */
//-(id) initOnGLMatrix: (GLfloat*) aGLMtx;
//
///**
// * Allocates and returns an initialized autoreleased instance that wraps the specified GL matrix,
// * which must be a standard 4x4 OpenGL matrix in column-major order. Changes to this matrix
// * instance will change the underlying data passed here. This is useful when the matrix data was
// * supplied and loaded by some other mechanism, such as a file loader. Rather than copying the
// * data into a new matrix, resulting in two copies of the matrix data, a CC3GLMatrix instance
// * can be initialized to wrap the data.
// */
//+(id) matrixOnGLMatrix: (GLfloat*) aGLMtx;
//
///**
// * Returns an initialized instance with elements populated from the specified
// * variable arguments, which must consist of 16 elements in column-major order.
// */
//-(id) initWithElements: (GLfloat) e00, ...;
//
///**
// * Allocates and returns an initialized autoreleased instance with elements populated from
// * the specified variable arguments, which must consist of 16 elements in column-major order.
// */
//+(id) matrixWithElements: (GLfloat) e00, ...;
//
//
//#pragma mark -
//#pragma mark Instance population
//
///** Populates this instance from data copied from the specified matrix instance. */
//-(void) populateFrom: (CC3GLMatrix*) aMtx;
//
///**
// * Populates this instance from data copied from the specified GL matrix,
// * which must be a standard 4x4 OpenGL matrix in column-major order.
// */
//-(void) populateFromGLMatrix: (GLfloat*) aGLMtx;
//
///** Populates this instance so that all elements are zero. */
//-(void) populateZero;
//
///** Populates this instance as an identity matrix (ones on the diagonal, zeros elsewhere). */
//-(void) populateIdentity;
//
///**
// * Populates this instance with the translation data provided by the specified translation vector.
// * The resulting matrix can be used to perform translation operations on other matrices through matrix multiplication.
// */
//-(void) populateFromTranslation: (CC3Vector) aVector;
//
///**
// * Populates this instance with the rotation data provided by the specified rotation vector.
// * Each element of the rotation vector represents an Euler angle in degrees,
// * and rotation is performed in YXZ order, which is the OpenGL default.
// *
// * The resulting matrix can be used to perform rotation operations on other matrices
// * through matrix multiplication.
// */
//-(void) populateFromRotation: (CC3Vector) aVector;
//
///**
// * Populates this instance with the rotation data provided by the specified quaternion.
// * The resulting matrix can be used to perform rotation operations on other matrices through matrix multiplication.
// */
//-(void) populateFromQuaternion: (CC3Vector4) aQuaternion;
//
///**
// * Populates this instance with the scaling data provided by the specified scaling vector.
// * The resulting matrix can be used to perform scaling operations on other matrices through matrix multiplication.
// */
//-(void) populateFromScale: (CC3Vector) aVector;
//
///**
// * Populates this matrix so that it will transform a vector pointed down the negative Z-axis to point in
// * the specified forwardDirection, and transforms the positive Y-axis to point in the specified upDirection.
// *
// * When applied to a targetting object (such as a camera, light, gun, etc), this has the effect of
// * pointing that object in a direction and orienting it so that 'up' is in the upDirection.
// *
// * This method works in model-space, and does not include an implied inversion. So, when applied to
// * the camera, this matrix must be subsequently inverted to transform from model-space to view-space.
// */
//-(void) populateToPointTowards: (CC3Vector) fwdDirection withUp: (CC3Vector) upDirection;
//
///**
// * Populates this matrix so that it will transform a vector between the targetLocation and the eyeLocation
// * to point along the negative Z-axis, and transforms the specified upDirection to the positive Y-axis.
// *
// * This transform works in the direction from model-space to view-space, and therefore
// * includes an implied inversion relative to the directToward:withUp: method. When applied to the camera,
// * this has the effect of locating the camera at the eyeLocation and pointing it at the targetLocation,
// * while orienting it so that 'up' appears to be in the upDirection, from the viewer's perspective.
// */
//-(void) populateToLookAt: (CC3Vector) targetLocation
//			   withEyeAt: (CC3Vector) eyeLocation
//				  withUp: (CC3Vector) upDirection;
//
///** Populates this matrix as a perspective projection matrix with the specified frustum dimensions. */
//-(void) populateFromFrustumLeft: (GLfloat) left
//					   andRight: (GLfloat) right
//					  andBottom: (GLfloat) bottom
//						 andTop: (GLfloat) top  
//						andNear: (GLfloat) near
//						 andFar: (GLfloat) far;
//
///** Populates this matrix as a parallel projection matrix with the specified frustum dimensions. */
//-(void) populateOrthoFromFrustumLeft: (GLfloat) left
//							andRight: (GLfloat) right
//						   andBottom: (GLfloat) bottom
//							  andTop: (GLfloat) top  
//							 andNear: (GLfloat) near
//							  andFar: (GLfloat) far;
//
//
//#pragma mark Matrix population
//
///**
// * Copies all data from the source matrix to the destination matrix.
// * Both matrices must be a standard 4x4 OpenGL matrices in column-major order.
// */
//+(void) copyMatrix: (GLfloat*) srcGLMatrix into: (GLfloat*) destGLMatrix;
//
///**
// * Populates the specified matrix so that it will transform a vector pointed down the negative Z-axis
// * to point in the specified forwardDirection, and transforms the positive Y-axis to point in the
// * specified upDirection. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// *
// * When applied to a targetting object (such as a camera, light, gun, etc), this has the effect of
// * pointing that object in a direction and orienting it so that 'up' is in the upDirection.
// *
// * This method works in model-space, and does not include an implied inversion. So, when applied to
// * the camera, this matrix must be subsequently inverted to transform from model-space to view-space.
// */
//+(void) populate: (GLfloat*) aGLMatrix toPointTowards: (CC3Vector) fwdDirection withUp: (CC3Vector) upDirection;
//
///**
// * Populates the specified matrix so that it will transform a vector between the targetLocation and
// * the eyeLocation to point along the negative Z-axis, and transforms the specified upDirection to
// * the positive Y-axis. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// *
// * This transform works in the direction from model-space to view-space, and therefore includes an
// * implied inversion relative to the directToward:withUp: method. When applied to the camera, this
// * has the effect of locating the camera at the eyeLocation and pointing it at the targetLocation,
// * while orienting it so that 'up' appears to be in the upDirection, from the viewer's perspective.
// */
//+(void) populate: (GLfloat*) aGLMatrix
//		toLookAt: (CC3Vector) targetLocation
//	   withEyeAt: (CC3Vector) eyeLocation
//		  withUp: (CC3Vector) upDirection;
//
///**
// * Populates the specified matrix as a perspective projection matrix with the specified
// * frustum dimensions. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) populate: (GLfloat*) aGLMatrix 
// fromFrustumLeft: (GLfloat) left
//		andRight: (GLfloat) right
//	   andBottom: (GLfloat) bottom
//		  andTop: (GLfloat) top  
//		 andNear: (GLfloat) near
//		  andFar: (GLfloat) far;
//
///**
// * Populates the specified matrix as a parallel projection matrix with the specified
// * frustum dimensions. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) populateOrtho: (GLfloat*) aGLMatrix 
//	  fromFrustumLeft: (GLfloat) left
//			 andRight: (GLfloat) right
//			andBottom: (GLfloat) bottom
//			   andTop: (GLfloat) top  
//			  andNear: (GLfloat) near
//			   andFar: (GLfloat) far;
//
//
//#pragma mark -
//#pragma mark Instance accessing
//
///**
// * Extracts the rotation component of this matrix and returns it as an Euler rotation vector,
// * assuming the rotations should be applied in YXZ order, which is the OpenGL default.
// * Each element of the returned rotation vector represents an Euler angle in degrees.
// */
//-(CC3Vector) extractRotation;
//
///** Extracts the rotation component of this matrix and returns it as a quaternion. */
//-(CC3Vector4) extractQuaternion;
//
///** Extracts and returns the 'forward' direction vector from the rotation component of this matrix. */
//-(CC3Vector) extractForwardDirection;
//
///** Extracts and returns the 'up' direction vector from the rotation component of this matrix. */
//-(CC3Vector) extractUpDirection;
//
///** Extracts and returns the 'right' direction vector from the rotation component of this matrix. */
//-(CC3Vector) extractRightDirection;
//
//
//#pragma mark Matrix accessing
//
///**
// * Extracts the rotation component of the specified matrix and returns it as an Euler rotation
// * vector, assuming the rotations should be applied in YXZ order, which is the OpenGL default.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// * Each element of the returned rotation vector represents an Euler angle in degrees.
// */
//+(CC3Vector) extractRotationYXZFromMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Extracts the rotation component of the specified matrix and returns it as an
// * Euler rotation vector, assuming the rotations should be applied in ZYX order.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// * Each element of the returned rotation vector represents an Euler angle in degrees.
// */
//+(CC3Vector) extractRotationZYXFromMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Extracts the rotation component of the specified matrix and returns it as a quaternion.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector4) extractQuaternionFromMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Extracts and returns the 'forward' direction vector from the rotation component of the specified matrix.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector) extractForwardDirectionFrom: (GLfloat*) aGLMatrix;
//
///**
// * Extracts and returns the 'up' direction vector from the rotation component of the specified matrix.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector) extractUpDirectionFrom: (GLfloat*) aGLMatrix;
//
///**
// * Extracts and returns the 'right' direction vector from the rotation component of the specified matrix.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector) extractRightDirectionFrom: (GLfloat*) aGLMatrix;
//
//
//#pragma mark -
//#pragma mark Instance transformations
//
///**
// * Translates, rotates and scales (in that order) this matrix by the specified amounts.
// * Each element of the rotation vector represents an Euler angle in degrees, and rotation
// * is performed in YXZ order, which is the OpenGL default.
// */
//-(void) translateBy: (CC3Vector) translationVector
//		   rotateBy: (CC3Vector) rotationVector
//			scaleBy: (CC3Vector) scaleVector;
//	
///**
// * Rotates this matrix by the specified amount. Each element of the rotation vector represents
// * an Euler angle in degrees, and rotation is performed in YXZ order, which is the OpenGL default.
// */
//-(void) rotateBy: (CC3Vector) aVector;
//
///** Rotates this matrix around the X-axis by the specified number of degrees. */
//-(void) rotateByX: (GLfloat) degrees;
//
///** Rotates this matrix around the Y-axis by the specified number of degrees. */
//-(void) rotateByY: (GLfloat) degrees;
//
///** Rotates this matrix around the Z-axis by the specified number of degrees. */
//-(void) rotateByZ: (GLfloat) degrees;
//
///** Rotates this matrix by the rotation specified in the given quaternion. */
//-(void) rotateByQuaternion: (CC3Vector4) aQuaternion;
//
///** Translates this matrix in three dimensions by the specified translation vector. */
//-(void) translateBy: (CC3Vector) aVector;
//
///** Translates this matrix along the X-axis by the specified amount. */
//-(void) translateByX: (GLfloat) distance;
//
///** Translates this matrix along the Y-axis by the specified amount. */
//-(void) translateByY: (GLfloat) distance;
//
///** Translates this matrix along the Z-axis by the specified amount. */
//-(void) translateByZ: (GLfloat) distance;
//
///**
// * Scales this matrix in three dimensions by the specified scaling vector. Non-uniform scaling
// * can be achieved by specifying different values for each element of the scaling vector.
// */
//-(void) scaleBy: (CC3Vector) aVector;
//
///** Scales this matrix along the X-axis by the specified factor. */
//-(void) scaleByX: (GLfloat) scaleFactor;
//
///** Scales this matrix along the Y-axis by the specified factor. */
//-(void) scaleByY: (GLfloat) scaleFactor;
//
///** Scales this matrix along the Z-axis by the specified factor. */
//-(void) scaleByZ: (GLfloat) scaleFactor;
//
///** Scales this matrix uniformly in three dimensions by the specified factor. */
//-(void) scaleUniformlyBy: (GLfloat) scaleFactor;
//
//
//#pragma mark Matrix transformations
//
///**
// * Translates, rotates and scales (in that order) the specified matrix by the specified amounts.
// * Each element of the rotation vector represents an Euler angle in degrees, and rotation
// * is performed in YXZ order, which is the OpenGL default.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) transform: (GLfloat*) aGLMatrix
//	  translateBy: (CC3Vector) translationVector
//		 rotateBy: (CC3Vector) rotationVector
//		  scaleBy: (CC3Vector) scaleVector;
//
///**
// * Rotates the specified matrix by the specified amount. Each element of the rotation vector represents
// * an Euler angle in degrees, and rotation is performed in YXZ order, which is the OpenGL default.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotateYXZ: (GLfloat*) aGLMatrix by: (CC3Vector) aVector;
//	
///**
// * Rotates the specified matrix by the specified amount. Each element of the rotation
// * vector represents an Euler angle in degrees, and rotation is performed in XYZ order.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotateZYX: (GLfloat*) aGLMatrix by: (CC3Vector) aVector;
//
///**
// * Rotates the specified matrix around the X-axis by the specified number of degrees.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotate: (GLfloat*) aGLMatrix byX: (GLfloat) degrees;
//
///**
// * Rotates the specified matrix around the Y-axis by the specified number of degrees.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotate: (GLfloat*) aGLMatrix byY: (GLfloat) degrees;
//
///**
// * Rotates the specified matrix around the Z-axis by the specified number of degrees.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotate: (GLfloat*) aGLMatrix byZ: (GLfloat) degrees;
//
///**
// * Rotates the specified matrix by the rotation specified in the given quaternion.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) rotate: (GLfloat*) aGLMatrix byQuaternion: (CC3Vector4) aQuaternion;
//
///**
// * Translates this matrix in three dimensions by the specified translation vector.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) translate: (GLfloat*) aGLMatrix by: (CC3Vector) aVector;
//
///**
// * Translates this matrix along the X-axis by the specified amount.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) translate: (GLfloat*) aGLMatrix byX: (GLfloat) distance;
//
///**
// * Translates this matrix along the Y-axis by the specified amount.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) translate: (GLfloat*) aGLMatrix byY: (GLfloat) distance;
//
///**
// * Translates this matrix along the Z-axis by the specified amount.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) translate: (GLfloat*) aGLMatrix byZ: (GLfloat) distance;
//
///**
// * Scales this matrix in three dimensions by the specified scaling vector. Non-uniform scaling
// * can be achieved by specifying different values for each element of the scaling vector.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) scale: (GLfloat*) aGLMatrix by: (CC3Vector) aVector;
//
///**
// * Scales this matrix along the X-axis by the specified factor.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) scale: (GLfloat*) aGLMatrix byX: (GLfloat) scaleFactor;
//
///**
// * Scales this matrix along the Y-axis by the specified factor.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) scale: (GLfloat*) aGLMatrix byY: (GLfloat) scaleFactor;
//
///**
// * Scales this matrix along the Z-axis by the specified factor.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) scale: (GLfloat*) aGLMatrix byZ: (GLfloat) scaleFactor;
//
///**
// * Scales this matrix uniformly in three dimensions by the specified factor.
// * The matrix must be standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) scale: (GLfloat*) aGLMatrix uniformlyBy: (GLfloat) scaleFactor;
//
//
//#pragma mark -
//#pragma mark Instance math operations
//
///**
// * Multiplies this matrix by the specified matrix.
// * The contents of this matrix are changed. The contents of the specified matrix remain unchanged.
// */
//-(void) multiplyByMatrix: (CC3GLMatrix*) aMatrix;
//
///**
// * Transforms the specified location vector using this matrix, and returns the transformed location.
// * During multiplication, the fourth element of the location vector is assumed to have a value of one.
// * This matrix and the original specified location vector remain unchanged.
// */
//-(CC3Vector) transformLocation: (CC3Vector) aLocation;
//
///**
// * Transforms the specified direction vector using this matrix, and returns the transformed direction.
// * During multiplication, the fourth element of the direction vector is assumed to have a value of zero.
// * This matrix and the original specified direction vector remain unchanged.
// */
//-(CC3Vector) transformDirection: (CC3Vector) aDirection;
//
///**
// * Transforms the specified homogeneous vector using this matrix, and returns the transformed homogeneous vector.
// * This matrix and the original specified homogeneous vector remain unchanged.
// */
//-(CC3Vector4) transformHomogeneousVector: (CC3Vector4) aVector;
//
///** Transposes this matrix. The contents of this matrix are changed. */
//-(void) transpose;
//
///**
// * Inverts this matrix using the Gauss-Jordan elimination algorithm. The contents of this matrix are changed.
// *
// * Gauss-Jordan elimination matrix inversion is an computationally-expensive algorithm. If it is known that
// * the matrix contains only rotation and translation, use the invertRigid method instead, which is between
// * one and two orders of magnitude faster than this method.
// * 
// * Also, be aware that rounding inaccuracies accumulated during the inversion calculations can often result
// * in the inverse of a matrix representing an affine transformation (the bottom row of the matrix is
// * {0, 0, 0 1}) that is not affine. These accumulated errors can often by significant when applied to the
// * bottom row and will affect further calculations. If it is known that a matrix represents an affine
// * transformation, use the invertAffine method instead, which forces the bottom row back to {0, 0, 0, 1}
// * after the inversion, to maintain the inverted matrix as an affine transformation. Affine transforms
// * include all combinations of rotation, scaling, shearing, translation, and orthographic projection,
// * so all matrices encountered while working with 3D graphics, with the exception of perspective projection,
// * will be affine transforms.
// */
//-(BOOL) invert;
//
///**
// * Inverts this matrix using the Gauss-Jordan elimination algorithm.
// * The contents of this matrix are changed.
// *
// * This method differs from the invert method in that it assumes that the matrix represents an affine
// * transform (the bottom row of the matrix is {0, 0, 0 1}), and that accumulated inaccuracies in the
// * inversion calculations should be removed from the bottom row of the resulting inverted matrix.
// * After inversion, it forces the bottom row of the inverted matrix back to {0, 0, 0 1}. This can be
// * quite useful, as this row is particularly sensitive to the accumulation of inaccuracies and can often
// * have a drastic impact on the accuracy of subsequent matrix and vector calculations. If it is known
// * that a matrix represents an affine transformation, use this method instead of the invert method.
// * Affine transforms include all combinations of rotation, scaling, shearing, translation,
// * and orthographic projection, so all matrices encountered while working with 3D graphics,
// * with the exception of perspective projection, will be affine transforms. 
// *
// * Gauss-Jordan elimination matrix inversion is an computationally-expensive algorithm. If it is known
// * that the matrix contains only rotation and translation, use the invertRigid method instead, which
// * is between one and two orders of magnitude faster than this method.
// */
//-(BOOL) invertAffine;
//
///**
// * Inverts this matrix using transposition and translation. The contents of this matrix are changed.
// *
// * This method assumes that the matrix represents a rigid transformation, containing only rotation and
// * translation. Use this method only if it is known that this is the case. Inversion of a rigid transform
// * matrix can be accomplished very quickly using transposition and translation, and is consistently one to
// * two orders of magnitude faster than the Gauss-Jordan elimination algorithm used by the invert and
// * invertAffine methods. It is recommended that this method be used wherever possible.
// */
//-(void) invertRigid;
//	
//
//#pragma mark Matrix math operations
//
///**
// * Multiplies a matrix by another matrix.
// * The contents of the first matrix are changed. The contents of the second matrix remain unchanged.
// * Both matrices must be a standard 4x4 OpenGL matrices in column-major order.
// */
//+(void) multiply: (GLfloat*) aGLMatrix byMatrix: (GLfloat*) anotherGLMatrix;
//
///**
// * Transforms the specified location vector using the specified matrix, and returns the transformed
// * location. During multiplication, the fourth element of the location vector is assumed to have a
// * value of one. The matrix and the original specified location vector remain unchanged.
// * The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector) transformLocation: (CC3Vector) aLocation withMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Transforms the specified direction vector using the specified matrix, and returns the transformed
// * direction. During multiplication, the fourth element of the location vector is assumed to have a
// * value of zero. The matrix and the original specified direction vector remain unchanged.
// * The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector) transformDirection: (CC3Vector) aDirection withMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Transforms the specified homogeneous vector using the specified matrix, and returns the transformed
// * homogeneous vector. The matrix and the original specified homogeneous vector remain unchanged.
// * The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(CC3Vector4) transformHomogeneousVector: (CC3Vector4) aVector withMatrix: (GLfloat*) aGLMatrix;
//
///**
// * Transposes the specified matrix. The contents of the matrix are changed.
// * The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// */
//+(void) transpose: (GLfloat*) aGLMatrix;
//
///**
// * Inverts the specified matrix using the Gauss-Jordan elimination algorithm. The contents of
// * the matrix are changed. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// *
// * Gauss-Jordan elimination matrix inversion is an computationally-expensive algorithm. If it is known that
// * the matrix contains only rotation and translation, use the invertRigid: method instead, which is between
// * one and two orders of magnitude faster than this method.
// * 
// * Also, be aware that rounding inaccuracies accumulated during the inversion calculations can often result
// * in the inverse of a matrix representing an affine transformation (the bottom row of the matrix is
// * {0, 0, 0 1}) that is not affine. These accumulated errors can often by significant when applied to the
// * bottom row and will affect further calculations. If it is known that a matrix represents an affine
// * transformation, use the invertAffine: method instead, which forces the bottom row back to {0, 0, 0, 1}
// * after the inversion, to maintain the inverted matrix as an affine transformation. Affine transforms
// * include all combinations of rotation, scaling, shearing, translation, and orthographic projection,
// * so all matrices encountered while working with 3D graphics, with the exception of perspective projection,
// * will be affine transforms.
// */
//+(BOOL) invert: (GLfloat*) aGLMatrix;
//
///**
// * Inverts the specified matrix using the Gauss-Jordan elimination algorithm. The contents of
// * the matrix are changed. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// *
// * This method differs from the invert: method in that it assumes that the matrix represents an affine
// * transform (the bottom row of the matrix is {0, 0, 0 1}), and that accumulated inaccuracies in the
// * inversion calculations should be removed from the bottom row of the resulting inverted matrix.
// * After inversion, it forces the bottom row of the inverted matrix back to {0, 0, 0 1}. This can be
// * quite useful, as this row is particularly sensitive to the accumulation of inaccuracies and can often
// * have a drastic impact on the accuracy of subsequent matrix and vector calculations. If it is known
// * that a matrix represents an affine transformation, use this method instead of the invert: method.
// * Affine transforms include all combinations of rotation, scaling, shearing, translation,
// * and orthographic projection, so all matrices encountered while working with 3D graphics,
// * with the exception of perspective projection, will be affine transforms. 
// *
// * Gauss-Jordan elimination matrix inversion is an computationally-expensive algorithm. If it is known
// * that the matrix contains only rotation and translation, use the invertRigid: method instead, which
// * is between one and two orders of magnitude faster than this method.
// */
//+(BOOL) invertAffine: (GLfloat*) aGLMatrix;
//
///**
// * Inverts the specified matrix using transposition and translation. The contents of this
// * matrix are changed. The matrix must be a standard 4x4 OpenGL matrix in column-major order.
// *
// * This method assumes that the matrix represents a rigid transformation, containing only rotation and
// * translation. Use this method only if it is known that this is the case. Inversion of a rigid transform
// * matrix can be accomplished very quickly using transposition and translation, and is consistently one
// * to two orders of magnitude faster than the Gauss-Jordan elimination algorithm used by the invert:
// * and invertAffine: methods. It is recommended that this method be used wherever possible.
// */
//+(void) invertRigid: (GLfloat*) aGLMatrix;
//
//@end

class CC3GLMatrix : public cocos2d::CCObject 
{
public:
	CC3GLMatrix();
	~CC3GLMatrix();
	
	CC_SYNTHESIZE(bool, isIdentity, IsIdentity);
	
	virtual GLfloat* getGlMatrix();
	
	virtual bool init();
	
	static CC3GLMatrix* matrix();
	
	virtual bool initIdentity();
	
	static CC3GLMatrix* identity();
	
	virtual bool initFromGLMatrix(GLfloat* aGLMtx);
	
	static CC3GLMatrix* matrixFromGLMatrix(GLfloat* aGLMtx);
	
	virtual bool initOnGLMatrix(GLfloat* aGLMtx);
	
	static CC3GLMatrix* matrixOnGLMatrix(GLfloat* aGLMtx);
	
	virtual bool initWithElements(GLfloat e00, ...);
	
	static CC3GLMatrix* matrixWithElements(GLfloat e00, ...);
	
	virtual bool initParent();
	
	virtual bool initWithFirstElement(GLfloat e00, va_list args);
	
	virtual void populateFrom(CC3GLMatrix* aMtx);
	
	virtual void populateFromGLMatrix(GLfloat* aGLMtx);
	
	virtual void populateZero();
	
	virtual void populateIdentity();
	
	virtual void populateFromTranslation(CC3Vector aVector);
	
	virtual void populateFromRotation(CC3Vector aVector);
	
	virtual void populateFromQuaternion(CC3Vector4 aQuaternion);
	
	virtual void populateFromScale(CC3Vector aVector);
	
	virtual void populateToPointTowards(CC3Vector fwdDirection, CC3Vector upDirection);
	
	virtual void populateToLookAt(CC3Vector targetLocation, CC3Vector eyeLocation, CC3Vector upDirection);
	
	virtual void populateFromFrustumLeft(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);
	
	void populateOrthoFromFrustumLeft(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);
	
	static void copyMatrix(GLfloat* srcGLMatrix, GLfloat* destGLMatrix);
	
	static void populate(GLfloat* aGLMatrix, CC3Vector fwdDirection, CC3Vector upDirection);
	
	static void populate(GLfloat* aGLMatrix, CC3Vector targetLocation, CC3Vector eyeLocation, CC3Vector upDirection);
	
	static void populate(GLfloat* aGLMatrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);
	
	static void populateOrtho(GLfloat* aGLMatrix, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far);
	
	void swap(GLuint idx1, GLuint idx);
	
	CC3Vector extractRotation();
	
	CC3Vector4 extractQuaternion();
	
	CC3Vector extractForwardDirection();
	
	CC3Vector extractUpDirection();
	
	CC3Vector extractRightDirection();
	
	static void swapInMatrix(GLuint idx1, GLuint, GLfloat* aGLMatrix);
	
	static CC3Vector extractRotationYXZFromMatrix(GLfloat* aGLMatrix);
	
	static CC3Vector extractRotationZYXFromMatrix(GLfloat* aGLMatrix);
	
	static CC3Vector4 extractQuaternionFromMatrix(GLfloat* aGLMatrix);
	
	static CC3Vector extractForwardDirectionFrom(GLfloat* aGLMatrix);
	
	static CC3Vector extractUpDirectionFrom(GLfloat* aGLMatrix);
	
	static CC3Vector extractRightDirectionFrom(GLfloat* aGLMatrix);
	
	void translateBy(CC3Vector translationVector, CC3Vector rotationVector, CC3Vector scaleVector);
	
	void rotateBy(CC3Vector aVector);
	
	void rotateByX(GLfloat degrees);
	
	void rotateByY(GLfloat degrees);
	
	void rotateByZ(GLfloat degrees);
	
	void rotateByQuaternion(CC3Vector4 aQuaternion);
	
	void translateBy(CC3Vector aVector);
	
	void translateByX(GLfloat distance);
	
	void translateByY(GLfloat distance);
	
	void translateByZ(GLfloat distance);
	
	void scaleBy(CC3Vector aVector);
	
	void scaleByX(GLfloat scaleFactor);
	
	void scaleByY(GLfloat scaleFactor);
	
	void scaleByZ(GLfloat scaleFactor);
	
	void scaleUniformlyBy(GLfloat scaleFactor);
	
	static void transform(GLfloat* aGLMatrix, CC3Vector translationVector, CC3Vector rotationVector, CC3Vector scaleVector);
	
	static void rotateYXZ(GLfloat* aGLMatrix, CC3Vector aVector);
	
	static void rotateZYX(GLfloat* aGLMatrix, CC3Vector aVector);
	
	static void rotateByX(GLfloat* aGLMatrix, GLfloat degrees);
	
	static void rotateByY(GLfloat* aGLMatrix, GLfloat degrees);
	
	static void rotateByZ(GLfloat* aGLMatrix, GLfloat degrees);
	
	static void rotateByQuaternion(GLfloat* aGLMatrix, CC3Vector4 aQuaternion);
	
	static void translateByVector(GLfloat* aGLMatrix, CC3Vector aVector);
	
	static void translateByX(GLfloat* aGLMatrix, GLfloat distance);
	
	static void translateByY(GLfloat* aGLMatrix, GLfloat distance);
	
	static void translateByZ(GLfloat* aGLMatrix, GLfloat distance);
	
	static void scaleByVector(GLfloat* aGLMatrix, CC3Vector aVector);
	
	static void scaleByX(GLfloat* aGLMatrix, GLfloat scaleFactor);
	
	static void scaleByY(GLfloat* aGLMatrix, GLfloat scaleFactor);
	
	static void scaleByZ(GLfloat* aGLMatrix, GLfloat scaleFactor);
	
	static void scaleUniformlyBy(GLfloat* aGLMatrix, GLfloat scaleFactor);
	
	void multiplyByMatrix(CC3GLMatrix* aMatrix);
	
	CC3Vector transformLocation(CC3Vector aLocation);
	
	CC3Vector transformDirection(CC3Vector aDirection);
	
	CC3Vector4 transformHomogeneousVector(CC3Vector4 aVector);
	
	void transpose();
	
	bool invert();
	
	bool invertAffine();
	
	void invertRigid();
	
	static void multiply(GLfloat* aGLMatrix, GLfloat* anotherGLMatrix);
	
	static CC3Vector transformLocation(CC3Vector aLocation, GLfloat* aGLMatrix);
	
	static CC3Vector transformDirection(CC3Vector aDirection, GLfloat* aGLMatrix);
	
	static CC3Vector4 transformHomogeneousVector(CC3Vector4 aVector, GLfloat* aGLMatrix);
	
	static void transpose(GLfloat* aGLMatrix);
	
	static bool invert(GLfloat* aGLMatrix);
	
	static bool invertAffine(GLfloat* aGLMatrix);
	
	static void invertRigid(GLfloat* aGLMatrix);
};

class CC3GLArrayMatrix : public CC3GLMatrix 
{
public:
	CC3GLArrayMatrix();
	~CC3GLArrayMatrix();
	
	virtual bool init();
	
	static CC3GLArrayMatrix* matrix();
	
	bool initIdentity();
	
	static CC3GLArrayMatrix* identity();
	
	bool initFromGLMatrix(GLfloat* aGLMtx);
	
	static CC3GLArrayMatrix* matrixFromGLMatrix(GLfloat* aGLMtx);
	
	bool initWithFirstElement(GLfloat e00, va_list args);
	
	GLfloat* getGlMatrix();
	
protected:
	GLfloat glArray[16];
};

class CC3GLPointerMatrix : public CC3GLMatrix 
{
public:
	CC3GLPointerMatrix();
	~CC3GLPointerMatrix();
	
	GLfloat* getGlMatrix();
	
	bool initOnGLMatrix(GLfloat* aGLMtx);
	
protected:
	GLfloat* glMatrix;
};

#endif //__CC3GLMATRIX_H__
